//Casa@131224a
#include<cmath>
#include<algorithm>
#include<vector>
#include<fstream>
#include<string>
using namespace std;

//-------------------------------------------------
//For OSHC
long long _find_max_vec(long long subvec[], int block_num, int block_size)
{
	int size = 1 << block_size;
	vector<int> num(size);
	fill(num.begin(), num.end(), 0);
	long long m[] = { 2, 1 };
	for (long long i = 0; i < size; i++)
	{
		long long t = 0;
		for (int x = 0; x < block_size; x++)
			t |= m[(i >> x) & 0x1] << (x << 1);
		for (int j = 0; j < block_num; j++)
		{
			long long f = t^subvec[j];
			if ((f&(f >> 1) & 0x5555555555555555) == 0)
			{
				num[i]++;
			}
		}
	}
	vector<int>::iterator p = max_element(num.begin(), num.end());
	long long ret = 0;
	int select = p - num.begin();
	for (int x = 0; x < block_size; x++)
		ret |= m[(select >> x) & 0x1] << (x << 1);
	return ret;
}
py::tuple _OSHC(long long subvec[], npy_intp block_num, int block_size, int encode_num)
{
	//vector<int> encode(encode_num+1);
	//vector<int> code_count(encode_num + 1,0);
	npy_intp dims[] = { encode_num+1 };
	PyArrayObject *p1 = (PyArrayObject *)PyArray_SimpleNew(1, dims, NPY_LONGLONG);
	long long* encode = (long long*)p1->data;
	PyArrayObject *p2 = (PyArrayObject *)PyArray_SimpleNew(1, dims, NPY_LONG);
	long* code_count = (long*)p2->data;
	fill(code_count, code_count + dims[0], 0);

	long long *pre = new long long[block_num];
	copy(subvec, subvec + block_num, pre);
	int pre_size = block_num;
	for (int i = 0; i < encode_num; i++)
	{
		vector<long long> now;
		for (int j = 0; j < pre_size;j++)
		if (pre[j] != 0)
			now.push_back(pre[j]);
		encode[i] = _find_max_vec(now.data(), now.size(), block_size);
		pre_size = 0;
		for (int k = 0; k < now.size(); k++)
		{
			long long t = encode[i] ^ now[k];
			if ((t&(t >> 1) & 0x5555555555555555) != 0)
				pre[pre_size++] = now[k];
		}
	}
	delete[] pre;
	encode[encode_num] = 0;
	for (int i = 0; i < block_num; i++)
	{
		for (int j = 0; j < dims[0]; j++)
		{
			long long t = subvec[i] ^ encode[j];
			if ((t&(t >> 1) & 0x5555555555555555) == 0)
			{
				code_count[j]++;
				break;
			}
		}
	}
	py::tuple results(2);
	results[0] = (PyObject *) p1;
	results[1] = (PyObject *) p2;
	return results;
}
//-----------------------------------------------------------------------
//vector to integer
PyObject * _vec2int(long *data, npy_intp Ndata[])
{
	npy_intp dims[] = { Ndata[0] };
	PyArrayObject *p = (PyArrayObject *)PyArray_SimpleNew(1, dims, NPY_LONGLONG);
	long long* d = (long long*)p->data;
	for (int i = 0; i < Ndata[0]; i++)
	{
		d[i] = 0;
		for (int j = 0; j < Ndata[1]; j++)
			d[i] |= ((long long)data[i*Ndata[1] + j])<< (j << 1);
	}
	return (PyObject *)p;
}
//integer to vector
PyObject * _int2vec(long long *data, int size, int block_size)
{
	npy_intp dims[] = { size, block_size };
	PyArrayObject *p = (PyArrayObject *)PyArray_SimpleNew(2, dims, NPY_LONG);
	long* d = (long*)p->data;
	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < block_size; j++)
			d[i*dims[1] + j] = (data[i] >> (j << 1)) & 0x3;
	}
	return (PyObject *)p;
}

//----------------------------------------------------------------
//FDR
int _FDR(long *data, int size)
{
	vector<int> _Dic(4096, -1);
	int fdr = 0;
	for (int i = 0; i < size; i++)
	{
		int l = 0;
		while (i < size&&data[i] != 1)
		{
			i++;
			l++;
		}
		if (_Dic[l] == -1)
		{
			int group = int(ceil((log(l + 3.0) / log(2.0) - 1)));
			_Dic[l] = group << 1;
		}
		fdr += _Dic[l];
	}
	return fdr;
}


